import os
import time
from datetime import datetime, timedelta
from apscheduler.schedulers.background import BackgroundScheduler
from .scheduled_jobs import cron_jobs, interval_jobs, date_jobs

from core.settings import settings

class Scheduler:
    """
    创建调度程序以管理保留任务
    https://apscheduler.readthedocs.io/en/3.x/modules/triggers/cron.html

    lib/scheduler/scheduled_jobs的 
    cron_schedules.py, interval_schedules.py, date_schedules.py将任务注册在.
    - cron_schedules.py: 每天我们都会记录在特定时间重复的任务.
    - interval_schedules.py: 注册要定期重复的任务.
    - date_schedules.py: 将任务注册为仅在特定日期和时间运行一次.
    """
    FLAG_DELETE_TIME = 10   # 单位: 秒
    flag_file_path = "data/flag.txt"
    job_ids = set()
    total_trigger_jobs = {
        "cron": cron_jobs,
        "interval": interval_jobs,
        "date": date_jobs,
    }

    def __init__(self) -> None:
        """
        创建并启动调度程序.
        默认情况下， BackgroundScheduler我使用.
        """
        self.background_scheduler = BackgroundScheduler(timezone=settings.TIME_ZONE)
        self.background_scheduler.start()

    def add_jobs(self, trigger_type: str) -> None:
        """
        在计划程序中注册触发器特定的任务.
        """
        trigger_jobs = self.total_trigger_jobs[trigger_type]
        for job_info in trigger_jobs:
            job_id, job_func, expression = job_info.values()
            self.background_scheduler.add_job(trigger=trigger_type, func=job_func, **expression)
            self.job_ids.add(job_id)

    def add_all_jobs(self) -> None:
        """
        在调度程序中注册所有触发器的所有任务.
        """
        for trigger_type in self.total_trigger_jobs.keys():
            self.add_jobs(trigger_type=trigger_type)

    @classmethod
    def is_flag_exist(cls) -> bool:
        """
        检查文件以确认计划程序注册。.
        """
        return os.path.exists(cls.flag_file_path)
    
    @classmethod
    def is_flag_valid(cls) -> bool:
        """
        通过比较文件创建时间和要删除的时间来检查用于调度程序注册的文件是否有效.
        - 删除时间: Scheduler.FLAG_DELETE_TIME (单位: second)
        - 如果您超过计划的删除时间 False返回.
        """
        file_creation_time = os.path.getmtime(cls.flag_file_path)
        current_time = time.time()
        if current_time - file_creation_time > cls.FLAG_DELETE_TIME:
            return False
        return True

    @classmethod
    def create_flag(cls) -> None:
        """
        我们为调度程序注册确认创建一个文件.
        """
        with open(cls.flag_file_path, "w") as f:
            f.write("Scheduler task has been registered.")

    @classmethod
    def remove_flag(cls) -> None:
        """
        删除用于计划程序注册确认的文件.
        """
        if os.path.exists(cls.flag_file_path):
            os.remove(cls.flag_file_path)

    def run_scheduler(self) -> None:
        """
        运行调度程序.
        - --workers 作为选项运行多个进程时 
          防止预订业务重复登记 flag我们使用.
        - flag 通过检查文件的有效性来确定是否创建文件以及是否注册计划任务.
        """
        time.sleep(0.1)
        if self.is_flag_exist() and self.is_flag_valid():
            return

        run_date = datetime.now() + timedelta(seconds=self.FLAG_DELETE_TIME)
        self.add_all_jobs()
        self.background_scheduler.add_job(
            trigger="date", func=self.remove_flag, run_date=run_date
        )
        self.create_flag()